﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Taxhui.Utils.IOUtils;

namespace Taxhui.Utils.CryptUtils
{
    public static class AESCrypt
    {
        #region 转换

        private static string ByteToStr(byte[] passByte)
        {
            return DataUtil.ByteToStr(passByte);
        }
        private static byte[] GetKeyByte(string key, int v, Encoding sEncode)
        {
            return DataUtil.GetKeyByte(key, v, sEncode);
        }
        #endregion
        #region AES加密解密
        /// <summary>
        /// //生成AES密钥
        /// </summary>
        /// <returns></returns>
        public static byte[] GetAESKey()
        {
            AesCryptoServiceProvider provider = new AesCryptoServiceProvider();
            provider.GenerateKey();
            provider.Dispose();
            byte[] key = provider.Key;
            return key;
        }
        public static string GetAESKey(Encoding encode = null)
        {
            encode = encode ?? Encoding.UTF8;
            return encode.GetString(GetAESKey());
        }
        /// <summary>
        /// 生成向量
        /// </summary>
        /// <returns></returns>
        public static byte[] GetAESKeyIV()
        {
            AesCryptoServiceProvider provider = new AesCryptoServiceProvider();
            provider.GenerateIV();
            byte[] iv = provider.IV;
            provider.Clear();
            provider.Dispose();
            return iv;
        }
        public static string GetAESKeyIV(Encoding encode = null)
        {
            encode = encode ?? Encoding.UTF8;
            return encode.GetString(GetAESKeyIV());
        }
        /// <summary>
        /// AES加密,密钥256位（32字节），向量128位（16字节）
        /// </summary>
        /// <param name="input">原文</param>
        /// <param name="key">密钥</param>
        /// <param name="keyIV">向量</param>
        /// <returns></returns>
        public static string AESEncrypt(string input, string key, string keyIV, Encoding sEncode = null, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
        {
            sEncode = sEncode ?? Encoding.UTF8;
            if (string.IsNullOrEmpty(input))
                throw new ArgumentNullException("原文不能为空！");
            byte[] data = sEncode.GetBytes(input);
            byte[] passByte = AESEncrypt(data, key, keyIV, sEncode, mode, padding);
            return ByteToStr(passByte);
        }

        public static byte[] AESEncrypt(byte[] input, string key, string keyIV, Encoding sEncode = null, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
        {
            byte[] keyByte = GetKeyByte(key, 32, sEncode);
            byte[] keyIVByte = GetKeyByte(keyIV, 16, sEncode);
            return AESEncrypt(input, keyByte, keyIVByte, mode, padding);
        }

        

        public static byte[] AESEncrypt(byte[] input, byte[] key, byte[] keyIV, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
        {
            Rijndael aes = Rijndael.Create();
            aes.Padding = padding;
            aes.Mode = mode;
            MemoryStream ms = new MemoryStream();
            CryptoStream cryptor = new CryptoStream(ms, aes.CreateEncryptor(key, keyIV), CryptoStreamMode.Write);
            cryptor.Write(input, 0, input.Length);
            cryptor.FlushFinalBlock();
            byte[] retByte = ms.ToArray();
            ms.Close();
            ms.Dispose();
            cryptor.Close();
            cryptor.Dispose();
            aes.Clear();
            aes.Dispose();
            return retByte;
        }

        public static string AESDecrypt(string enStr, string key, string keyIV, Encoding sEncode = null, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
        {
            sEncode = sEncode ?? Encoding.UTF8;
            byte[] dataByte = Convert.FromBase64String(enStr);
            return ByteToStr(AESDecrypt(dataByte, key, keyIV, sEncode, mode, padding));
        }
        public static byte[] AESDecrypt(byte[] passData, string key, string keyIV, Encoding sEncode = null, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
        {
            sEncode = sEncode ?? Encoding.UTF8;
            byte[] keyByte = GetKeyByte(key, 32, sEncode);
            byte[] keyIVByte = GetKeyByte(keyIV, 16, sEncode);
            return AESDecrypt(passData, keyByte, keyIVByte, mode, padding);
        }
        public static byte[] AESDecrypt(byte[] passData, byte[] key, byte[] keyIV, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
        {
            Rijndael aes = Rijndael.Create();
            aes.Mode = mode;
            aes.Padding = padding;
            MemoryStream ms = new MemoryStream(passData);
            CryptoStream cryptor = new CryptoStream(ms, aes.CreateDecryptor(key, keyIV), CryptoStreamMode.Read);
            MemoryStream orgStream = new MemoryStream();
            byte[] buf = new byte[1024];
            int read;
            do
            {
                read = cryptor.Read(buf, 0, buf.Length);
                if (read > 0)
                    orgStream.Write(buf, 0, read);
            } while (read > 0);
            byte[] data = orgStream.ToArray();
            orgStream.Close(); orgStream.Dispose();
            cryptor.Close(); cryptor.Dispose();
            ms.Close(); ms.Dispose();
            aes.Clear();
            aes.Dispose();
            return data;
        }
        #endregion
    }
}
